<script setup lang="ts">
import { computed, nextTick, onUnmounted, ref, watch } from 'vue'
import { Rank } from '@element-plus/icons-vue'
import { ElMessageBox } from 'element-plus'
import Sortable, { type SortableEvent } from 'sortablejs'
import type { ExtendedColumnConfig } from '@/types/table'

// ==================== 常量配置 ====================

/** Sortable.js 配置常量 */
const SORTABLE_CONFIG = {
  // 动画配置
  ANIMATION_DURATION: 150,
  DELAY: 100,

  // 滚动配置
  SCROLL_SENSITIVITY: 40,
  SCROLL_SPEED: 15,

  // CSS 类名
  CLASSES: {
    GHOST: 'sortable-ghost',
    CHOSEN: 'sortable-chosen',
    DRAG: 'sortable-drag',
    ACTIVE: 'sortable-drag-active',
  },

  // 选择器
  SELECTORS: {
    CONTAINER: '.table-column-setting .sortable-list',
    HANDLE: '.col-drag',
  },
} as const

/** 滚动位置判断阈值 */
const SCROLL_THRESHOLD = 50

/** 预定义颜色 */
const colColor = ref<string[]>([
  '#f0f9ff',
  '#fefce8',
  '#f0fdf4',
  '#fef7ff',
  '#fff7ed',
  '#f8fafc',
  '#ecfdf5',
  '#fef3c7',
  '#ddd6fe',
  '#fed7d7',
])

const colTextColor = ref<string[]>([
  '#000000',
  '#333333',
  '#666666',
  '#999999',
  '#ff4d4f',
  '#52c41a',
  '#1890ff',
  '#722ed1',
  '#fa8c16',
  '#eb2f96',
])

// Props
interface Props {
  modelValue: boolean
  columns: ExtendedColumnConfig[]
  dialogTitle?: string
  dialogWidth?: string
}

const props = withDefaults(defineProps<Props>(), {
  dialogTitle: '表格设置',
  dialogWidth: '90%',
})

// Emits
const emit = defineEmits<{
  'update:modelValue': [value: boolean]
  'update:columns': [columns: ExtendedColumnConfig[]]
  'columns-change': [columns: ExtendedColumnConfig[]]
  'restore-default': []
}>()

// ==================== 类型定义 ====================

/** 拖拽事件类型 */
interface DragEvent {
  oldIndex: number
  newIndex: number
  totalItems: number
}

// ==================== 状态管理 ====================

// 拖拽排序实例
let sortableInstance: Sortable | null = null

// 保存滚动位置的变量
let savedScrollTop = 0

// 计算属性：控制对话框显示
const visible = computed({
  get: () => props.modelValue,
  set: (value) => emit('update:modelValue', value),
})

// 本地列配置（深拷贝，避免直接修改父组件数据）
const localColumns = ref<ExtendedColumnConfig[]>([])

// 初始化扩展属性的函数
const initializeColumnConfig = (
  column: ExtendedColumnConfig,
  index: number,
): ExtendedColumnConfig => {
  // 生成默认标题
  const getDefaultTitle = (col: ExtendedColumnConfig): string => {
    if (col.title) return col.title
    if (col.type === 'checkbox') return ''
    if (col.type === 'seq') return '序号列'
    if (col.field) return col.field
    return '未命名列'
  }

  return {
    ...column,
    visible: column.visible !== undefined ? column.visible : true,
    color: column.color || '',
    textColor: column.textColor || '',
    sortIndex: column.sortIndex !== undefined ? column.sortIndex : index + 1,
    align: column.align || 'center',
    headerAlign: column.headerAlign || 'center',
    originalTitle: column.originalTitle || getDefaultTitle(column),
  }
}

// 监听 props.columns 变化，同步到本地
watch(
  () => props.columns,
  (newColumns) => {
    localColumns.value = newColumns.map((col, index) =>
      initializeColumnConfig(JSON.parse(JSON.stringify(col)), index),
    )
  },
  { immediate: true, deep: true },
)

// ==================== 工具函数 ====================

/**
 * 获取滚动容器元素
 */
const getScrollContainer = (): Element | null => {
  return document.querySelector(SORTABLE_CONFIG.SELECTORS.CONTAINER)
}

/**
 * 处理拖拽开始事件
 */
const handleDragStart = (): void => {
  const sortableList = getScrollContainer()
  if (sortableList) {
    // 保存当前滚动位置
    savedScrollTop = sortableList.scrollTop
    // 添加拖拽激活状态（CSS会自动禁用平滑滚动）
    sortableList.classList.add(SORTABLE_CONFIG.CLASSES.ACTIVE)
  }
}

/**
 * 更新列配置数据
 */
const updateColumnConfigs = (evt: SortableEvent): void => {
  if (evt.oldIndex !== undefined && evt.newIndex !== undefined) {
    const newColumnConfigs = [...localColumns.value]
    const [movedItem] = newColumnConfigs.splice(evt.oldIndex, 1)
    newColumnConfigs.splice(evt.newIndex, 0, movedItem)

    // 更新sortIndex
    newColumnConfigs.forEach((item, index) => {
      item.sortIndex = index + 1
    })

    localColumns.value = newColumnConfigs
  }
}

/**
 * 判断是否为极端位置拖拽（第一个↔最后一个）
 */
const isExtremeDrag = (dragEvent: DragEvent): boolean => {
  const { oldIndex, newIndex, totalItems } = dragEvent
  const isFirstToLast = oldIndex === 0 && newIndex === totalItems - 1
  const isLastToFirst = oldIndex === totalItems - 1 && newIndex === 0
  return isFirstToLast || isLastToFirst
}

/**
 * 智能滚动位置恢复
 */
const handleScrollRestore = (evt: SortableEvent, sortableList: Element): void => {
  if (evt.oldIndex === undefined || evt.newIndex === undefined) return

  const dragEvent: DragEvent = {
    oldIndex: evt.oldIndex,
    newIndex: evt.newIndex,
    totalItems: localColumns.value.length,
  }

  const currentScrollTop = sortableList.scrollTop

  if (isExtremeDrag(dragEvent)) {
    // 极端位置拖拽：保持用户拖拽过程中的自然滚动位置
    // 不做任何强制滚动调整
    return
  }

  // 普通拖拽：智能判断是否需要恢复原位置
  const scrollDiff = Math.abs(currentScrollTop - savedScrollTop)
  if (scrollDiff <= SCROLL_THRESHOLD) {
    // 滚动差距较小，恢复到原位置
    sortableList.scrollTop = savedScrollTop
  }
  // 滚动差距较大时，保持当前位置
}

/**
 * 处理拖拽结束事件
 */
const handleDragEnd = (evt: SortableEvent): void => {
  const sortableList = getScrollContainer()

  // 更新数据
  updateColumnConfigs(evt)

  // 使用nextTick确保DOM更新完成后再恢复滚动状态
  nextTick(() => {
    if (sortableList) {
      // 移除拖拽激活状态
      sortableList.classList.remove(SORTABLE_CONFIG.CLASSES.ACTIVE)
      // 智能滚动位置恢复
      handleScrollRestore(evt, sortableList)
    }
  })
}

/**
 * 创建Sortable配置对象
 */
const createSortableConfig = () => ({
  // 拖拽手柄选择器
  handle: SORTABLE_CONFIG.SELECTORS.HANDLE,
  // 动画配置
  animation: SORTABLE_CONFIG.ANIMATION_DURATION,
  delayOnTouchOnly: true,
  delay: SORTABLE_CONFIG.DELAY,
  // CSS类名配置
  ghostClass: SORTABLE_CONFIG.CLASSES.GHOST,
  chosenClass: SORTABLE_CONFIG.CLASSES.CHOSEN,
  dragClass: SORTABLE_CONFIG.CLASSES.DRAG,
  // 滚动配置
  scroll: true,
  scrollSensitivity: SORTABLE_CONFIG.SCROLL_SENSITIVITY,
  scrollSpeed: SORTABLE_CONFIG.SCROLL_SPEED,
  bubbleScroll: true,
  forceAutoScrollFallback: true,
  // 其他配置
  forceFallback: false,
  fallbackTolerance: 0,
  dragoverBubble: false,
  // 事件回调
  onStart: handleDragStart,
  onEnd: handleDragEnd,
})

/**
 * 初始化拖拽排序
 */
const initSortable = (): void => {
  nextTick(() => {
    const el = getScrollContainer()
    if (el && !sortableInstance) {
      sortableInstance = Sortable.create(el as HTMLElement, createSortableConfig())
    }
  })
}

/**
 * 销毁拖拽排序实例
 */
const destroySortable = (): void => {
  if (sortableInstance) {
    sortableInstance.destroy()
    sortableInstance = null
  }
}

// ==================== 事件处理函数 ====================

/**
 * 打开设置对话框
 */
const handleOpen = (): void => {
  initSortable()
}

/**
 * 关闭设置对话框（取消操作）
 * 重置所有本地配置到初始状态
 */
const handleClose = (): void => {
  destroySortable()
  // 深拷贝重置本地配置
  localColumns.value = props.columns.map((col, index) =>
    initializeColumnConfig(JSON.parse(JSON.stringify(col)), index),
  )
  visible.value = false
}

/**
 * 确认并应用配置
 * 将本地配置提交到父组件
 */
const handleConfirm = (): void => {
  const updatedColumns = JSON.parse(JSON.stringify(localColumns.value))
  emit('update:columns', updatedColumns)
  emit('columns-change', updatedColumns)
  destroySortable()
  visible.value = false
}

/**
 * 处理背景颜色变化
 */
const handleColorChange = (column: ExtendedColumnConfig, color: string): void => {
  column.color = color
}

/**
 * 处理字体颜色变化
 */
const handleTextColorChange = (column: ExtendedColumnConfig, color: string): void => {
  column.textColor = color
}

/**
 * 处理固定列设置变化
 */
const handleFixedChange = (column: ExtendedColumnConfig, value: string): void => {
  if (value === 'none') {
    delete column.fixed
  } else {
    column.fixed = value as 'left' | 'right'
  }
}

/**
 * 恢复默认配置
 * 显示确认对话框，确认后触发恢复事件
 */
const handleRestoreDefault = async (): Promise<void> => {
  try {
    await ElMessageBox.confirm('此操作将清除所有自定义设置，是否继续？', '确认恢复默认配置', {
      confirmButtonText: '确定',
      cancelButtonText: '取消',
      type: 'warning',
    })
    emit('restore-default')
  } catch (error) {
    // 用户取消操作，不做任何处理
  }
}

// 监听对话框打开/关闭
watch(visible, (newVisible) => {
  if (newVisible) {
    handleOpen()
  } else {
    handleClose()
  }
})

// 组件卸载时清理
onUnmounted(() => {
  destroySortable()
})
</script>

<template>
  <el-dialog
    v-model="visible"
    :title="dialogTitle"
    :width="dialogWidth"
    @close="handleClose"
    :close-on-click-modal="false"
    class="table-column-setting"
    style="height: calc(100vh - 200px); margin-top: 100px"
  >
    <div class="settings-container">
      <div class="settings-table">
        <div class="table-header">
          <div class="col-drag"></div>
          <div class="col-name">列名</div>
          <div class="col-default-name">默认列名</div>
          <div class="col-visible">显示</div>
          <div class="col-width">宽度</div>
          <div class="col-align">对齐</div>
          <div class="col-fixed">固定</div>
          <div class="col-color">背景色</div>
          <div class="col-text-color">字体色</div>
        </div>
        <div class="sortable-list">
          <div
            v-for="(col, index) in localColumns"
            :key="col.field || col.type || `column-${index}`"
            class="column-item"
            :data-id="col.field || col.type || `column-${index}`"
          >
            <div class="col-drag">
              <el-icon class="drag-handle">
                <Rank />
              </el-icon>
            </div>
            <div class="col-name">
              <span class="sort-index">{{ col.sortIndex }}</span>
              <el-input v-model="col.title" size="small" style="width: calc(100% - 30px)" />
            </div>
            <div class="col-default-name">
              <span class="default-title-text">{{ col.originalTitle }}</span>
            </div>
            <div class="col-visible">
              <el-switch v-model="col.visible" size="small" />
            </div>
            <div class="col-width">
              <el-input-number
                v-model="col.width"
                :min="50"
                :max="500"
                :step="10"
                size="small"
                controls-position="right"
              />
            </div>
            <div class="col-align">
              <el-radio-group v-model="col.align" size="small">
                <el-radio-button label="left">左</el-radio-button>
                <el-radio-button label="center">中</el-radio-button>
                <el-radio-button label="right">右</el-radio-button>
              </el-radio-group>
            </div>
            <div class="col-fixed">
              <el-select
                :model-value="col.fixed || 'none'"
                size="small"
                placeholder="选择固定"
                @change="(value: string) => handleFixedChange(col, value)"
              >
                <el-option label="不固定" value="none" />
                <el-option label="左固定" value="left" />
                <el-option label="右固定" value="right" />
              </el-select>
            </div>
            <div class="col-color">
              <el-color-picker
                v-model="col.color"
                size="small"
                show-alpha
                :predefine="colColor"
                @change="(color: string) => handleColorChange(col, color)"
              />
            </div>
            <div class="col-text-color">
              <el-color-picker
                v-model="col.textColor"
                size="small"
                show-alpha
                :predefine="colTextColor"
                @change="(color: string) => handleTextColorChange(col, color)"
              />
            </div>
          </div>
        </div>
      </div>
    </div>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="handleRestoreDefault" style="margin-right: auto"> 恢复默认 </el-button>
        <el-button @click="handleClose">取消</el-button>
        <el-button type="primary" @click="handleConfirm">确定</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">
// ==================== SCSS 变量定义 ====================

// 主题色系 - 使用 Element Plus CSS 变量
$primary-color: var(--el-color-primary);
$primary-light: var(--el-color-primary-light-7);
$primary-lighter: var(--el-color-primary-light-8);
$primary-ultra-light: var(--el-color-primary-light-9);
$primary-gradient-start: $primary-lighter;
$primary-gradient-end: $primary-light;

// 中性色系
$white: #ffffff;
$gray-50: #f8f9fa;
$gray-100: #f5f7fa;
$gray-200: #f1f1f1;
$gray-300: #f0f0f0;
$gray-400: #dee2e6;
$gray-500: #c1c1c1;
$gray-600: #c0c4cc;
$gray-700: #a8a8a8;
$gray-800: #909399;
$gray-900: #606266;

// 边框色系
$border-color: #e4e7ed;
$border-light: $gray-300;
$border-dashed: $gray-400;

// 文本色系
$text-primary: $gray-900;
$text-secondary: $gray-800;
$text-disabled: $gray-600;

// 阴影色系 - 基于 Element Plus 主题色
$shadow-primary: color-mix(in srgb, var(--el-color-primary) 10%, transparent);
$shadow-primary-strong: color-mix(in srgb, var(--el-color-primary) 15%, transparent);
$shadow-primary-ultra: color-mix(in srgb, var(--el-color-primary) 2%, transparent);
$shadow-outline: color-mix(in srgb, var(--el-color-primary) 30%, transparent);
$shadow-dark-light: rgba(0, 0, 0, 0.08);
$shadow-dark-medium: rgba(0, 0, 0, 0.12);

// 特殊颜色 - 使用 Element Plus 主题色
$gradient-blue: var(--el-color-primary-light-3);
$transparent: transparent;

// 尺寸变量
$border-radius-sm: 4px;
$border-radius-md: 6px;
$border-radius-lg: 8px;
$border-radius-xl: 12px;

// 动画变量
$transition-fast: all 0.2s ease;
$transition-normal: all 0.3s ease;

// ==================== 主容器样式 ====================

.settings-container {
  height: calc(100vh - 320px);
  display: flex;
  flex-direction: column;

  // ==================== 表格容器 ====================

  .settings-table {
    display: flex;
    flex-direction: column;
    border: 1px solid $border-color;
    border-radius: $border-radius-sm;
    flex: 1;
    min-height: 0;

    // 表格头部
    .table-header {
      display: grid;
      grid-template-columns: 40px 2fr 1.5fr 80px 120px 180px 120px 120px 120px;
      gap: 12px;
      padding: 12px 32px 12px 16px;
      background: $gray-100;
      font-weight: 500;
      color: $text-primary;
      font-size: 14px;
      text-align: center;
      flex-shrink: 0;

      .col-name {
        text-align: center;
      }
    }

    .sortable-list {
      flex: 1;
      overflow-y: auto;
      overflow-x: hidden;
      position: relative;
      min-height: 0;
      scroll-behavior: smooth;

      &.sortable-drag-active {
        background: radial-gradient(circle at center, rgba(64, 158, 255, 0.02) 0%, transparent 70%);
        // 拖拽状态下禁用平滑滚动，避免与拖拽动画冲突
        scroll-behavior: auto !important;

        // 拖拽状态下禁用所有transition，避免动画冲突
        .column-item {
          transition: none !important;

          &::before {
            transition: none !important;
          }

          // 禁用hover效果，避免拖拽时意外触发
          &:hover {
            background: inherit;
            box-shadow: none;
            transform: none;

            &::before {
              background: transparent;
              width: 3px;
            }
          }
        }
      }

      &::-webkit-scrollbar {
        width: 8px;
      }

      &::-webkit-scrollbar-track {
        background: $gray-200;
        border-radius: $border-radius-sm;
      }

      &::-webkit-scrollbar-thumb {
        background: $gray-500;
        border-radius: $border-radius-sm;

        &:hover {
          background: $gray-700;
        }
      }

      .column-item {
        display: grid;
        grid-template-columns: 40px 2fr 1.5fr 80px 120px 180px 120px 120px 120px;
        gap: 12px;
        padding: 12px 16px;
        border-bottom: 1px solid $gray-300;
        transition: $transition-normal;
        position: relative;

        &::before {
          content: '';
          position: absolute;
          left: 0;
          top: 0;
          bottom: 0;
          width: 3px;
          background: $transparent;
          transition: $transition-normal;
          border-radius: 0 2px 2px 0;
        }

        &:hover {
          background: linear-gradient(135deg, $primary-ultra-light 0%, $primary-lighter 100%);
          //transform: translateX(2px);
          box-shadow: 0 2px 8px $shadow-primary;

          &::before {
            background: linear-gradient(to bottom, $primary-color, $gradient-blue);
            width: 4px;
          }
        }

        &:last-child {
          border-bottom: none;
        }

        .col-drag {
          display: flex;
          align-items: center;
          justify-content: center;

          .drag-handle {
            color: $gray-600;
            font-size: 23px;
            cursor: grab;
            transition: $transition-fast;
            padding: 4px;
            border-radius: $border-radius-sm;

            &:hover {
              color: $primary-color;
              background: $primary-lighter;
              transform: scale(1.1);
            }

            &:active {
              cursor: grabbing;
              transform: scale(0.95);
              background: $primary-light;
            }
          }
        }

        .col-name {
          display: flex;
          align-items: center;
          color: $text-primary;
          gap: 8px;

          .sort-index {
            background: $primary-light;
            color: $gradient-blue;
            padding: 2px;
            border-radius: 12px;
            font-size: 12px;
            font-weight: 500;
            width: 30px;
            text-align: center;
          }
        }

        .col-default-name {
          display: flex;
          align-items: center;
          justify-content: flex-start;
          padding-left: 8px;

          .default-title-text {
            color: $text-secondary;
            font-size: 13px;
            padding: 4px 8px;
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
          }
        }

        .col-visible,
        .col-width,
        .col-align,
        .col-fixed,
        .col-color,
        .col-text-color {
          display: flex;
          align-items: center;
          justify-content: center;
        }

        .col-width {
          :deep(.el-input-number) {
            width: 100px;

            .el-input__inner {
              text-align: center;
            }
          }
        }

        .col-align {
          :deep(.el-radio-group) {
            .el-radio-button__inner {
              padding: 4px 8px;
              font-size: 12px;
            }
          }
        }

        .col-fixed {
          :deep(.el-select) {
            width: 100px;

            .el-input__inner {
              font-size: 12px;
            }
          }
        }
      }
    }
  }
}

// 拖拽状态样式
.sortable-ghost {
  opacity: 0.4 !important;
  background: $gray-50 !important;
  border: 2px dashed $border-dashed !important;
  border-radius: $border-radius-md !important;
  // 使用transform3d启用硬件加速，减少重绘
  transform: translate3d(0, 0, 0) scale(0.98) !important;
  // 禁用transition避免与sortable动画冲突
  transition: none !important;
  // 提升层级避免其他元素干扰
  z-index: 1 !important;

  // 禁用ghost状态下的所有内部动画
  * {
    transition: none !important;
  }
}

.sortable-chosen {
  background: linear-gradient(135deg, $primary-lighter 0%, $primary-light 100%) !important;
  border: 1px solid $primary-color !important;
  border-radius: $border-radius-md !important;
  // 使用transform3d启用硬件加速
  transform: translate3d(0, 0, 0) scale(1.01) !important;
  // 禁用transition，让sortable完全控制动画
  transition: none !important;
  box-shadow: 0 2px 12px $shadow-primary-strong !important;
  cursor: grab !important;
  z-index: 10 !important;
}

.sortable-drag {
  background: $white !important;
  box-shadow:
    0 8px 25px $shadow-dark-medium,
    0 4px 12px $shadow-dark-light,
    0 0 0 2px $shadow-outline !important;
  border-radius: $border-radius-lg !important;
  // 使用transform3d启用硬件加速，减少缩放比例减少闪动
  transform: translate3d(0, 0, 0) scale(1.02) !important;
  border: 1px solid $primary-color !important;
  cursor: grabbing !important;
  // 禁用transition，完全由sortable控制
  transition: none !important;
  // 最高层级确保不被遮挡
  z-index: 1000 !important;

  // 禁用拖拽元素内部的所有动画
  * {
    transition: none !important;
    pointer-events: none !important;
  }
}
</style>
